package com.unibeta.cloudtest.mesher.config;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;

import com.unibeta.cloudtest.config.plugin.elements.SpringBeanFactoryPlugin;
import com.unibeta.cloudtest.servlet.CloudTestServlet;
import com.unibeta.cloudtest.tool.Tools;
import com.unibeta.cloudtest.util.CloudTestUtils;
import com.unibeta.vrules.servlets.VRules4jServlet;

@Configuration
@RestController
public class CloudTestBootStrap implements ApplicationContextAware {

	public static final String CLOUDTEST_HOME = "";

	private static ApplicationContext applicationContext = null;

	@Autowired
	private static DataSource DataSource;

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public static DataSource getDataSource() {
		return DataSource;
	}

	@Bean
	public ServletRegistrationBean cloudTestServletRegistrationBean() {

		ServletRegistrationBean bean = new ServletRegistrationBean(new CloudTestServlet());

		bean.addInitParameter("CLOUDTEST_HOME$PathProvider",
				"com.unibeta.cloudtest.config.impl.CLOUDTEST_HOME$PathProviderImpl");
		bean.addInitParameter("ROOT_FOLDER_NAME", "cloudtest");
		bean.addInitParameter("WEBSERVICE_ENDPOINT_ADDRESS", "/services/cloudtest");
		bean.addUrlMappings("/services/cloudtest/*");
		bean.setLoadOnStartup(5);

		return bean;
	}

	@Bean
	public ServletRegistrationBean getVRules4jServletServletRegistrationBean() {

		URL url = Thread.currentThread().getContextClassLoader().getResource("");
		if ("jar".equalsIgnoreCase(url.getProtocol())) {
			String[] paths = url.getPath().split(".jar!");
			Tools.setXspringboot(paths[0].split("file:")[1] + ".jar");
		}

		ServletRegistrationBean bean = new ServletRegistrationBean(new VRules4jServlet());

		bean.addUrlMappings("/vrules4j/*");
		bean.setLoadOnStartup(1);

		return bean;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	public static class SpringBeanFactoryPluginImpl implements SpringBeanFactoryPlugin {

		private ApplicationContext getApplicationContext() {
			return CloudTestBootStrap.getApplicationContext();
		}

		@Override
		public Object getBean(String name) throws BeansException {

			return getApplicationContext().getBean(name);
		}

		@Override
		public <T> T getBean(String name, Class<T> requiredType) throws BeansException {

			return getApplicationContext().getBean(name, requiredType);
		}

		@Override
		public Object getBean(String name, Object... args) throws BeansException {

			return getApplicationContext().getBean(name, args);
		}

		@Override
		public <T> T getBean(Class<T> requiredType) throws BeansException {

			return getApplicationContext().getBean(requiredType);
		}

		@Override
		public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {

			return getApplicationContext().getBean(requiredType, args);
		}

		@Override
		public boolean containsBean(String name) {

			return getApplicationContext().containsBean(name);
		}

		@Override
		public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {

			return getApplicationContext().isSingleton(name);
		}

		@Override
		public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {

			return getApplicationContext().isPrototype(name);
		}

		@Override
		public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException {

			return getApplicationContext().isTypeMatch(name, typeToMatch);
		}

		@Override
		public Class<?> getType(String name) throws NoSuchBeanDefinitionException {

			return getApplicationContext().getType(name);
		}

		@Override
		public String[] getAliases(String name) {

			return getApplicationContext().getAliases(name);
		}

		@Override
		public boolean containsBeanDefinition(String beanName) {

			return getApplicationContext().containsBeanDefinition(beanName);
		}

		@Override
		public int getBeanDefinitionCount() {

			return getApplicationContext().getBeanDefinitionCount();
		}

		@Override
		public String[] getBeanDefinitionNames() {

			return getApplicationContext().getBeanDefinitionNames();
		}

		@Override
		public String[] getBeanNamesForType(Class<?> type) {

			return getApplicationContext().getBeanNamesForType(type);
		}

		@Override
		public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {

			return getApplicationContext().getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
		}

		@Override
		public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {

			return getApplicationContext().getBeansOfType(type);
		}

		@Override
		public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
				throws BeansException {

			return getApplicationContext().getBeansOfType(type, includeNonSingletons, allowEagerInit);
		}

		@Override
		public String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType) {

			return getApplicationContext().getBeanNamesForAnnotation(annotationType);
		}

		@Override
		public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
				throws BeansException {

			return getApplicationContext().getBeansWithAnnotation(annotationType);
		}

		@Override
		public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
				throws NoSuchBeanDefinitionException {

			return getApplicationContext().findAnnotationOnBean(beanName, annotationType);
		}

		@Override
		public Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
			// TODO Auto-generated method stub
			return null;
		}

	}

	public static class XLSUtils {

		/**
		 * load xls dataset from xls file.
		 * 
		 * @param url
		 * @return
		 * @throws Exception
		 */
		public static LinkedHashMap<String, List<LinkedHashMap<String, Object>>> load(String filePath)
				throws Exception {
			return loadXls(filePath);
		}

		/**
		 * Exports the dataset to xls file.
		 * 
		 * @param fileName target xls file path
		 * @param dataset  of LinkedHashMap<String, List<LinkedHashMap<String, Object>>>
		 * @throws Exception
		 */
		public static void save(LinkedHashMap<String, List<LinkedHashMap<String, Object>>> dataset, String fileName)
				throws Exception {

			Workbook workbook = new HSSFWorkbook(); // 创建工作簿对象
			for (String title : dataset.keySet()) {

				List<LinkedHashMap<String, Object>> dataList = dataset.get(title);
				try {

					Sheet sheet = workbook.createSheet(title); // 创建工作表
					CellStyle columnTopStyle = getColumnTopStyle(workbook);// 获取列头样式对象
					CellStyle style = getStyle(workbook); // 单元格样式对象

// 定义所需列数
					int columnNum = dataList.get(0).size();
					Row rowRowName = sheet.createRow(0); // 在索引2的位置创建行(最顶端的行开始的第二行)

// 将列头设置到sheet的单元格中
					int n = 0;
					for (String key : dataList.get(0).keySet()) {
						Cell cellRowName = rowRowName.createCell(n++); // 创建列头对应个数的单元格
// cellRowName.setCellType(HSSFCell.CELL_TYPE_STRING); // 设置列头单元格的数据类型
						HSSFRichTextString text = new HSSFRichTextString(key);
						cellRowName.setCellValue(text); // 设置列头单元格的值
						cellRowName.setCellStyle(columnTopStyle); // 设置列头单元格样式
					}

// 将查询出的数据设置到sheet对应的单元格中
					for (int i = 0; i < dataList.size(); i++) {

						Object[] obj = dataList.get(i).values().toArray();// 遍历每个对象
						Row row = sheet.createRow(i + 1);// 创建所需的行数

						for (int j = 0; j < obj.length; j++) {
							Cell cell = null; // 设置单元格的数据类型

							cell = row.createCell(j, CellType.STRING);
							if (!"".equals(obj[j]) && obj[j] != null) {
								cell.setCellValue(obj[j].toString()); // 设置单元格的值
							}

							cell.setCellStyle(style); // 设置单元格样式
						}
					}
// // 让列宽随着导出的列长自动适应
// for (int colNum = 0; colNum < columnNum; colNum++) {
// int columnWidth = sheet.getColumnWidth(colNum) / 256;
// for (int rowNum = 0; rowNum < sheet.getLastRowNum();
// rowNum++) {
// Row currentRow;
// // 当前行未被使用过
// if (sheet.getRow(rowNum) == null) {
// currentRow = sheet.createRow(rowNum);
// } else {
// currentRow = sheet.getRow(rowNum);
// }
// if (currentRow.getCell(colNum) != null) {
// Cell currentCell = currentRow.getCell(colNum);
// if (currentCell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
// int length = currentCell.getStringCellValue()
// .getBytes().length;
// if (columnWidth < length) {
// columnWidth = length;
// }
// }
// }
// }
// if (colNum == 0) {
// sheet.setColumnWidth(colNum, (columnWidth - 2) * 256);
// } else {
// sheet.setColumnWidth(colNum, (columnWidth + 4) * 256);
// }
// }

				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			CloudTestUtils.checkFile(fileName);
			FileOutputStream xls = new FileOutputStream(fileName);
			workbook.write(xls);
			xls.close();
		}

		/*
		 * 列头单元格样式
		 */
		static CellStyle getColumnTopStyle(Workbook workbook) {
//
// // 设置字体
// Font font = workbook.createFont();
// // 设置字体大小
// font.setFontHeightInPoints((short) 11);
// // 字体加粗
// font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
// // 设置字体名字
// font.setFontName("Arial");
// // 设置样式;
			CellStyle style = workbook.createCellStyle();
// // 设置底边框;
// style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
// // 设置底边框颜色;
// style.setBottomBorderColor(HSSFColor.BLACK.index);
// // 设置左边框;
// style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
// // 设置左边框颜色;
// style.setLeftBorderColor(HSSFColor.BLACK.index);
// // 设置右边框;
// style.setBorderRight(HSSFCellStyle.BORDER_THIN);
// // 设置右边框颜色;
// style.setRightBorderColor(HSSFColor.BLACK.index);
// // 设置顶边框;
// style.setBorderTop(HSSFCellStyle.BORDER_THIN);
// // 设置顶边框颜色;
// style.setTopBorderColor(HSSFColor.BLACK.index);
// // 在样式用应用设置的字体;
// style.setFont(font);
// // 设置自动换行;
// style.setWrapText(false);
// // 设置水平对齐的样式为居中对齐;
// style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// // 设置垂直对齐的样式为居中对齐;
// style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
//
			return style;

		}

//
// /*
// * 列数据信息单元格样式
// */
		static CellStyle getStyle(Workbook workbook) {
// 设置字体
			Font font = workbook.createFont();
// 设置字体大小
// font.setFontHeightInPoints((short)10);
// 字体加粗
// font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
// 设置字体名字
			font.setFontName("Arial");
// 设置样式;
			CellStyle style = workbook.createCellStyle();
// 设置底边框;
// style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
// // 设置底边框颜色;
// style.setBottomBorderColor(HSSFColor.BLACK.index);
// // 设置左边框;
// style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
// // 设置左边框颜色;
// style.setLeftBorderColor(HSSFColor.BLACK.index);
// // 设置右边框;
// style.setBorderRight(HSSFCellStyle.BORDER_THIN);
// // 设置右边框颜色;
// style.setRightBorderColor(HSSFColor.BLACK.index);
// // 设置顶边框;
// style.setBorderTop(HSSFCellStyle.BORDER_THIN);
// // 设置顶边框颜色;
// style.setTopBorderColor(HSSFColor.BLACK.index);
// // 在样式用应用设置的字体;
// style.setFont(font);
// // 设置自动换行;
// style.setWrapText(false);
// // 设置水平对齐的样式为居中对齐;
// style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// // 设置垂直对齐的样式为居中对齐;
// style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

			return style;

		}

		private static LinkedHashMap<String, List<LinkedHashMap<String, Object>>> loadXls(String filePath)
				throws Exception {

			LinkedHashMap<String, List<LinkedHashMap<String, Object>>> xmlmap = new LinkedHashMap<String, List<LinkedHashMap<String, Object>>>();

			Workbook wb = getWorkbook(filePath);
			if (wb == null) {
				throw new Exception("invalid or unsupported file path is: '" + filePath + "'");
			}

			Iterator<Sheet> it = wb.sheetIterator();
			while (it.hasNext()) {

				ArrayList<String> columns = new ArrayList<String>();
				List<LinkedHashMap<String, Object>> list = new ArrayList<LinkedHashMap<String, Object>>();
				Sheet sheet = it.next();

				for (int i = 0; i <= sheet.getLastRowNum(); i++) {
					LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
					Row row = sheet.getRow(i);

					if (row != null) {
						for (int j = 0; j < sheet.getRow(0).getLastCellNum(); j++) {
							Object cellData = getCellFormatValue(row.getCell(j));
							if (i == 0) {
								columns.add(cellData.toString());
							} else {
								map.put(columns.get(j), cellData);
							}
						}

					} else {
						break;
					}
					if (i > 0) {
						list.add(map);
					}
				}

				xmlmap.put(sheet.getSheetName(), list);
			}

			wb.close();
			return xmlmap;
		}

		static Workbook getWorkbook(String filePath) {
			Workbook wb = null;

			if (filePath == null
					|| (!filePath.toLowerCase().endsWith(".xls") && !filePath.toLowerCase().endsWith(".xlsx"))) {
				return null;
			}

			String extString = filePath.substring(filePath.lastIndexOf("."));
			InputStream is = null;
			try {
				is = new FileInputStream(filePath);
				if (".xls".equalsIgnoreCase(extString)) {
					wb = new HSSFWorkbook(is);
				} else if (".xlsx".equalsIgnoreCase(extString)) {
					wb = new XSSFWorkbook(is);
				}

			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return wb;
		}

		private static Object getCellFormatValue(Cell cell) {
			Object cellValue = null;

// if(null ==cell) {
// return null;
// }

// if(DateUtil.isCellDateFormatted(cell)) {
// return cell.getDateCellValue();
// }else if(cell.getCellType().equals(CellType.BOOLEAN)){
// return cell.getBooleanCellValue();
// }else{
// cell.setCellType(CellType.STRING);
// return cell.getRichStringCellValue().toString();
// }

			if (cell != null) {
				switch (cell.getCellType()) {
				case NUMERIC: {
					if (DateUtil.isCellDateFormatted(cell)) {
						cellValue = cell.getDateCellValue();

					} else {
						BigDecimal df = new BigDecimal((Double) cell.getNumericCellValue());
						cellValue = cell.getNumericCellValue();// df.toPlainString();

					}
					break;
				}
				case FORMULA: {
					if (DateUtil.isCellDateFormatted(cell)) {
						cellValue = cell.getDateCellValue();

					} else {
						BigDecimal df = new BigDecimal((Double) cell.getNumericCellValue());
						cellValue = cell.getNumericCellValue();// df.toPlainString();

					}
					break;
				}
				case STRING: {
					cellValue = cell.getRichStringCellValue().getString();
					break;
				}
				case BOOLEAN: {
					cellValue = cell.getBooleanCellValue();
					break;
				}
				default: {
					cellValue = cell.getRichStringCellValue().toString();
				}
				}
			} else {
				cellValue = "";
			}

			return cellValue;
		}

	}
}
